package my.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.Resource;

import my.service.RepositoryMessageSource;
import my.util.Log;

@Configuration
public class MessageSourceConfiguration {
    @Autowired
    ApplicationContext applicationContext;



    @Bean
    @ConditionalOnMissingBean
    MessageSourceAccessor messageSourceAccessor() {
        return new MessageSourceAccessor(applicationContext);
    }



    // ConditionalOnMissingBean 如果@Bean的返回type一样的 会被忽略.

    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(prefix = "messageSource.repository")
    RepositoryMessageSource repositoryMessageSource() {
        return new RepositoryMessageSource();
    }



    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(prefix = "messageSource.reloadableResourceBundle")
    ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource() {
        ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource() {
            @SuppressWarnings("unused")
            public void setBasenameSet(String... pBasenames) {
                setBasenames(pBasenames);
            }



            @Override
            protected Properties loadProperties(Resource pResource, String pFilename) throws IOException {
                Properties props = super.loadProperties(pResource, pFilename);
                logger.info("Loaded message properties [" + pResource.getFilename() + " : " + props.size() + "]");
                return props;
            }
        };

        // some configuration.
        source.setUseCodeAsDefaultMessage(true);
        String basenames = applicationContext.getEnvironment().getProperty("messageSource.reloadableResourceBundle.basenameSet");
        if (StringUtils.isEmpty(basenames)) {
            source.addBasenames("classpath:/messageSources/messageSource", "file:./config/messageSources/messageSource");
        }
        return source;
    }



    /**
     * 合并的,共用的MessageSource.
     * @return
     */
    @Bean(AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME)
    @ConditionalOnMissingBean
    @Primary
    CompositeMessageSource messageSource() {
        return new CompositeMessageSource()
            .addSource(repositoryMessageSource())
            .addSource(reloadableResourceBundleMessageSource());
    }

    /**
     * 多个MessageSource 按顺序直到找到为止.
     * @author Hubert
     */
    class CompositeMessageSource implements MessageSource {
        final Log                 log     = Log.of(getClass());
        final List<MessageSource> sources = new ArrayList<>(2);



        public CompositeMessageSource addSource(MessageSource... pMessageSources) {
            if (ArrayUtils.isNotEmpty(pMessageSources)) {
                sources.addAll(Arrays.asList(pMessageSources));
            }
            return this;
        }



        @Override
        public String getMessage(String pCode, Object[] pArgs, String pDefaultMessage, Locale pLocale) {
            for (MessageSource source : sources) {
                String result = source.getMessage(pCode, pArgs, pDefaultMessage, pLocale);
                if (StringUtils.isNotEmpty(result)) {
                    return result;
                }
            }
            log.warn("not exist message key or not have value. message key: {0}, locale: {1}", pCode, pLocale);
            return null;
        }



        @Override
        public String getMessage(String pCode, Object[] pArgs, Locale pLocale) throws NoSuchMessageException {
            for (MessageSource source : sources) {
                String result = source.getMessage(pCode, pArgs, pLocale);
                if (StringUtils.isNotEmpty(result)) {
                    return result;
                }
            }
            log.warn("not exist message key or not have value. message key: {0}, locale: {1}", pCode, pLocale);
            return null;
        }



        @Override
        public String getMessage(MessageSourceResolvable pResolvable, Locale pLocale) throws NoSuchMessageException {
            for (MessageSource source : sources) {
                String result = source.getMessage(pResolvable, pLocale);
                if (StringUtils.isNotEmpty(result)) {
                    return result;
                }
            }
            log.warn("not exist message key or not have value. message key: {0}, locale: {1}", Arrays.toString(pResolvable.getCodes()),
                pLocale.toString());
            return null;
        }

    }
}
